package cn.joinhealth.effect.spark.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author yuan
 * @description xml工具 用于解析sql
 * @date 2022/3/10 13:36
 */
public class XmlUtils {

    private static final Logger logger = LoggerFactory.getLogger(XmlUtils.class);

    /**
     * Date日期格式化
     */
    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * LocalDateTime日期时间格式化
     */
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 解析xml中的sql语句
     *
     * @param sqlId sqlId
     * @param map   参数
     * @return sql
     */
    public static String getSql(String sqlId, Map<String, Object> map) {
        Environment environment = new Environment("development", new JdbcTransactionFactory(), new PooledDataSource());
        Configuration configuration = new Configuration(environment);
        configuration.getTypeAliasRegistry().registerAliases("cn.joinhealth.spark.dao");
        configuration.addMappers("cn.joinhealth.spark.dao");

        BoundSql boundSql = configuration.getMappedStatement(sqlId).getBoundSql(map);
        String sql = boundSql.getSql();

        if (StringUtils.isBlank(sql)) {
            return "";
        }
        sql = sql.replaceAll("[\\s\n]+", " ");

        Object parameterObj = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();

        List<String> parameters = new ArrayList<>();
        if (null != parameterMappings) {
            MetaObject metaObject = parameterObj == null ? null : configuration.newMetaObject(parameterObj);
            for (ParameterMapping parameterMapping : parameterMappings) {
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (null == parameterObj) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObj.getClass())) {
                        value = parameterObj;
                    } else {
                        value = metaObject == null ? null : metaObject.getValue(propertyName);
                    }

                    if (value instanceof Number) {
                        parameters.add(String.valueOf(value));
                    } else {
                        StringBuilder sb = new StringBuilder();
                        sb.append("'");
                        if (value instanceof Date) {
                            sb.append(SIMPLE_DATE_FORMAT.format((Date) value));
                        } else if (value instanceof LocalDateTime) {
                            sb.append(DATE_TIME_FORMATTER.format((LocalDateTime) value));
                        } else if (value instanceof String) {
                            sb.append(value);
                        }
                        sb.append("'");
                        parameters.add(sb.toString());
                    }
                }
            }
        }
        for (String value : parameters) {
            sql = sql.replaceFirst("\\?", value);
        }
        logger.info("[解析XMl生成SQL]结果: {}", sql);
        return sql;
    }
}
